実践!AWS CDK #32 Secrets Manager Stack
題字・息子たち
はじめに
今回は Secrets Manager のスタックを実装していきます。
前回の記事はこちら。
実装
追加するファイルは以下の通り。
├── lib │ ├── resource │ │ └── secret.ts │ └── stack │ └── secrets-manager-stack.ts ├── test │ └── stack │ └── secrets-manager-stack.test.ts
Secrets Manager のスタッククラスの実装はこちら。
import { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import { Secret } from '../resource/secret'; export class SecretsManagerStack extends Stack { public readonly secret: Secret; constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); this.secret = new Secret(this); } }
自前の Secret
クラスのインスタンスを生成しています。他のリソースとの依存関係はないため、コンストラクタにスタックオブジェクトのパラメーターはありません。
以下が Secret
クラスの実装です。
以前からの変更も特になし。
import { CfnSecret } from "aws-cdk-lib/aws-secretsmanager"; import { Construct } from "constructs"; import { BaseResource } from "./abstract/base-resouce"; export const OSecretKey = { MasterUsername: 'MasterUsername', MasterUserPassword: 'MasterUserPassword' } as const; type SecretKey = typeof OSecretKey[keyof typeof OSecretKey]; interface ResourceInfo { readonly id: string; readonly description: string; readonly generateSecretString: CfnSecret.GenerateSecretStringProperty; readonly resourceName: string; readonly assign: (secret: CfnSecret) => void; } export class Secret extends BaseResource { public readonly rdsCluster: CfnSecret; private static readonly rdsClusterMasterUsername = 'admin'; private readonly resources: ResourceInfo[] = [{ id: 'SecretRdsCluster', description: 'for RDS cluster', generateSecretString: { excludeCharacters: '"@/\\\'', generateStringKey: OSecretKey.MasterUserPassword, passwordLength: 16, secretStringTemplate: `{"${OSecretKey.MasterUsername}": "${Secret.rdsClusterMasterUsername}"}` }, resourceName: 'secret-rds-cluster', assign: secret => (this.rdsCluster as CfnSecret) = secret }]; constructor(scope: Construct) { super(); for (const resourceInfo of this.resources) { const secret = this.createSecret(scope, resourceInfo); resourceInfo.assign(secret); } } public static getDynamicReference(secret: CfnSecret, secretKey: SecretKey): string { return `{{resolve:secretsmanager:${secret.ref}:SecretString:${secretKey}}}`; } private createSecret(scope: Construct, resourceInfo: ResourceInfo): CfnSecret { const secret = new CfnSecret(scope, resourceInfo.id, { description: resourceInfo.description, generateSecretString: resourceInfo.generateSecretString, name: this.createResourceName(scope, resourceInfo.resourceName) }); return secret; } }
メインのスタッククラスの実装はこちら。
import { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import { Ec2Stack } from './stack/ec2-stack'; import { IamStack } from './stack/iam-stack'; import { SecretsManagerStack } from './stack/secrets-manager-stack'; import { VpcStack } from './stack/vpc-stack'; export class DevioStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); // VPC Stack const vpcStack = new VpcStack(scope, 'VpcStack', { stackName: this.createStackName(scope, 'vpc') }); // IAM Stack const iamStack = new IamStack(scope, 'IamStack', { stackName: this.createStackName(scope, 'iam') }); // EC2 Stack new Ec2Stack(scope, 'Ec2Stack', vpcStack, iamStack, { stackName: this.createStackName(scope, 'ec2') }); // Secrets Manager Stack new SecretsManagerStack(scope, 'SecretsManagerStack', { stackName: this.createStackName(scope, 'secrets-manager') }); } private createStackName(scope: Construct, originalName: string): string { const systemName = scope.node.tryGetContext('systemName'); const envType = scope.node.tryGetContext('envType'); const stackNamePrefix = `${systemName}-${envType}-stack-`; return `${stackNamePrefix}${originalName}`; } }
ハイライト部分を追記しています。
テスト
テストコードはこちら。
import { App } from 'aws-cdk-lib'; import { Template } from 'aws-cdk-lib/assertions'; import { SecretsManagerStack } from '../../lib/stack/secrets-manager-stack'; test('Secrets Manager Stack', () => { const app = new App({ context: { 'systemName': 'devio', 'envType': 'stg' } }); const secretsManagerStack = new SecretsManagerStack(app, 'SecretsManagerStack'); const template = Template.fromStack(secretsManagerStack); template.resourceCountIs('AWS::SecretsManager::Secret', 1); template.hasResourceProperties('AWS::SecretsManager::Secret', { Description: 'for RDS cluster', GenerateSecretString: { ExcludeCharacters: '"@/\\\'', GenerateStringKey: 'MasterUserPassword', PasswordLength: 16, SecretStringTemplate: '{"MasterUsername": "admin"}' }, Name: 'devio-stg-secret-rds-cluster' }); });
GitHub
今回のソースコードは コチラ です。
おわりに
スタック分割リファクタイングもいよいよ終盤です。残るは RDS スタックのみ。次回、最終回です。